package util

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"errors"
	"google.golang.org/grpc"
	"google.golang.org/grpc/connectivity"
	"sync"
	"time"
	grpc2 "gitee.com/zxs-micro/zxs-micro-common/grpc"
	"gitee.com/zxs-micro/zxs-micro-auth/grpc/authserver/model"
	"gitee.com/zxs-micro/zxs-micro-common/grpc/clients"
	"gitee.com/zxs-micro/zxs-micro-common/log"
	"gitee.com/zxs-micro/zxs-micro-auth/protos/auth"
)

type CommonAuthClient struct {
	c auth.AuthsClient
	clients.CommonClients
}

var authClients = make(map[string]*CommonAuthClient)
var clock sync.Mutex

func GenerateAuthClient(addr string) (*CommonAuthClient, error) {
	var err error
	clock.Lock()
	cli, ok := authClients[addr]
	clock.Unlock()
	if !ok {
		cli = new(CommonAuthClient)
		cli.ClientConn, err = grpc.Dial(addr, grpc2.GetClientDialOpts()...)
		if err != nil {
			return nil, err
		}
		cli.c = auth.NewAuthsClient(cli.ClientConn)
		cli.RemoteAddr = addr
		clock.Lock()
		authClients[addr] = cli
		clock.Unlock()
	}
	return cli, nil
}

func (c *CommonAuthClient) CheckAuths(token, url string) error {
	err := c.CheckConn()
	if err != nil {
		return err
	}
	resp, err := c.c.Accept(context.Background(), &auth.AuthAcceptRequest{
		AccessToken: token,
		RequestUrl:  url,
	})
	if err != nil {
		return err
	}
	if !resp.IsSuccess {
		return errors.New("访问被拒绝！")
	}
	return nil
}

func (c *CommonAuthClient) Login(account, role string) (string, error) {
	err := c.CheckConn()
	if err != nil {
		return "", err
	}
	resp, err := c.c.Login(context.Background(), &auth.LoginRequest{
		LoginAccount: account,
		LoginRole:    role,
	})
	if err != nil {
		return "", err
	}
	if !resp.IsSuccess {
		return "", errors.New("登录失败！")
	}
	return resp.AuthToken, nil
}

func (c *CommonAuthClient) CheckConn() (err error) {
	c.ClientLock.Lock()
	if c.ClientConn.GetState() == connectivity.Shutdown {
		c.ClientConn, err = grpc.Dial(c.RemoteAddr, grpc2.GetClientDialOpts()...)
		c.c = auth.NewAuthsClient(c.ClientConn)
	}
	c.ClientLock.Unlock()
	return
}

func (c *CommonAuthClient) ShutdownClient() {
	c.ClientLock.Lock()
	c.ClientConn.Close()
	c.ClientLock.Unlock()
	clock.Lock()
	delete(authClients, c.RemoteAddr)
	clock.Unlock()
}

func (c *CommonAuthClient) Token2Model(str string) (*model.TokenModel, error) {
	err := c.CheckConn()
	if err != nil {
		return nil, err
	}
	resp, err := c.c.FindLoginUser(context.Background(), &auth.FindLoginUserRequest{
		Token: str,
	})
	if err != nil {
		return nil, err
	}
	return &model.TokenModel{
		Account:    resp.Account,
		Role:       resp.Role,
		Creator:    resp.Creator,
		CreateTime: time.Unix(resp.CreateTime, 0),
		LastTime:   time.Unix(resp.LastTime, 0),
	}, nil
}

func Token2Model(str string) (*model.TokenModel, error) {
	m := new(model.TokenModel)
	bs, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		log.Log.Error("解析用户token失败！")
		return nil, err
	}
	err = json.Unmarshal(bs, &m)
	return m, err
}
